GPS + INS¶
Position and orientation of Polar 5 and Polar 6 are recorded by an on-board GPS sensor and the internal navigation system (INS). The following example presents the variables recored by these instruments.
Data access¶
To load the data we first load the (AC)³airborne meta data catalogue. More information on the catalog can be found here.
import ac3airborne
GPS and INS data of Polar 5
cat = ac3airborne.get_intake_catalog()
list(cat.Polar5.GPS_INS)
['ACLOUD_P5_RF04',
'ACLOUD_P5_RF05',
'ACLOUD_P5_RF06',
'ACLOUD_P5_RF07',
'ACLOUD_P5_RF08',
'ACLOUD_P5_RF10',
'ACLOUD_P5_RF11',
'ACLOUD_P5_RF13',
'ACLOUD_P5_RF14',
'ACLOUD_P5_RF15',
'ACLOUD_P5_RF16',
'ACLOUD_P5_RF17',
'ACLOUD_P5_RF18',
'ACLOUD_P5_RF19',
'ACLOUD_P5_RF20',
'ACLOUD_P5_RF21',
'ACLOUD_P5_RF22',
'ACLOUD_P5_RF23',
'ACLOUD_P5_RF25',
'AFLUX_P5_RF02',
'AFLUX_P5_RF03',
'AFLUX_P5_RF04',
'AFLUX_P5_RF05',
'AFLUX_P5_RF06',
'AFLUX_P5_RF07',
'AFLUX_P5_RF08',
'AFLUX_P5_RF09',
'AFLUX_P5_RF10',
'AFLUX_P5_RF11',
'AFLUX_P5_RF12',
'AFLUX_P5_RF13',
'AFLUX_P5_RF14',
'AFLUX_P5_RF15',
'MOSAiC-ACA_P5_RF02',
'MOSAiC-ACA_P5_RF03',
'MOSAiC-ACA_P5_RF04',
'MOSAiC-ACA_P5_RF05',
'MOSAiC-ACA_P5_RF06',
'MOSAiC-ACA_P5_RF07',
'MOSAiC-ACA_P5_RF08',
'MOSAiC-ACA_P5_RF09',
'MOSAiC-ACA_P5_RF10',
'MOSAiC-ACA_P5_RF11']
GPS and INS data of Polar 6
list(cat.Polar6.GPS_INS)
['ACLOUD_P6_RF07',
'ACLOUD_P6_RF08',
'ACLOUD_P6_RF09',
'ACLOUD_P6_RF10',
'ACLOUD_P6_RF11',
'ACLOUD_P6_RF12',
'ACLOUD_P6_RF13',
'ACLOUD_P6_RF14',
'ACLOUD_P6_RF15',
'ACLOUD_P6_RF16',
'ACLOUD_P6_RF17',
'ACLOUD_P6_RF18',
'ACLOUD_P6_RF19',
'ACLOUD_P6_RF20',
'ACLOUD_P6_RF21',
'ACLOUD_P6_RF22',
'ACLOUD_P6_RF23',
'ACLOUD_P6_RF24',
'ACLOUD_P6_RF25']
Note
Have a look at the attributes of the xarray dataset ds_gps_ins for all relevant information on the dataset, such as author, contact, or citation infromation.
ds_gps_ins = cat['Polar5']['GPS_INS']['AFLUX_P5_RF10'].to_dask()
ds_gps_ins
<xarray.Dataset>
Dimensions: (time: 17808)
Coordinates:
* time (time) datetime64[ns] 2019-04-03T10:06:26 ... 2019-04-03T15:03:23
Data variables:
alt (time) float64 nan 30.14 30.13 30.13 ... 26.04 26.06 26.09 nan
tas (time) float64 nan 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 nan
lat (time) float64 nan 78.25 78.25 78.25 ... 78.25 78.25 78.25 nan
lat_dir (time) object '' 'N' 'N' 'N' 'N' 'N' 'N' ... 'N' 'N' 'N' 'N' 'N' ''
lon (time) float64 nan 15.5 15.5 15.5 15.5 ... 15.5 15.5 15.5 15.5 nan
lon_dir (time) object '' 'E' 'E' 'E' 'E' 'E' 'E' ... 'E' 'E' 'E' 'E' 'E' ''
vs (time) float64 nan 0.0 -0.0 -0.0 0.0 0.0 ... -0.0 -0.0 -0.0 0.0 nan
gs (time) float64 0.0 0.0 0.0 0.02 0.02 ... 3.22 3.19 3.19 3.2 3.19
pitch (time) float64 11.61 11.61 11.61 11.61 ... 11.23 11.23 11.23 11.23
roll (time) float64 1.21 1.21 1.22 1.21 1.22 ... 1.33 1.33 1.33 1.33
heading (time) float64 -76.76 -76.76 -76.76 -76.76 ... -71.94 -71.94 -71.95
Attributes: (12/14)
description: 1Hz subset based on GPS1 and INS data processed by AWI engi...
instruments: GPS1 and INS
version: [0.1]
contact: mario.mech@uni-koeln.de, martin.gehrmann@awi.de
institution: ['Alfred-Wegener-Institut Helmholtz-Zentrum für Polar- und ...
author: Dr. Mario Mech
... ...
featureType: trajectory
mission: AFLUX
platform: Polar5
flight_id: RF10
title: Polar5 position and attitude data
history: acquired by Polar5 during AFLUX campaign, quality checked b...- time: 17808
- time(time)datetime64[ns]2019-04-03T10:06:26 ... 2019-04-...
- standard_name :
- time
- long_name :
- time in seconds since epoch
- axis :
- T
array(['2019-04-03T10:06:26.000000000', '2019-04-03T10:06:27.000000000', '2019-04-03T10:06:28.000000000', ..., '2019-04-03T15:03:21.000000000', '2019-04-03T15:03:22.000000000', '2019-04-03T15:03:23.000000000'], dtype='datetime64[ns]')
- alt(time)float64...
- standard_name :
- height_above_reference_ellipsoid
- long_name :
- WGS84 datum/elliptical height
- positive :
- up
- units :
- m
- axis :
- Z
array([ nan, 30.14, 30.13, ..., 26.06, 26.09, nan])
- tas(time)float64...
- standard_name :
- platform_speed_wrt_air
- long_name :
- calculated true airspeed
- coordiantes :
- lon lat alt
- units :
- m/s
array([nan, 0., 0., ..., 0., 0., nan])
- lat(time)float64...
- standard_name :
- latitude
- long_name :
- WGS84 datum/latitude
- units :
- degrees_north
- axis :
- Y
array([ nan, 78.24589 , 78.24589 , ..., 78.245885, 78.245885, nan])
- lat_dir(time)object...
array(['', 'N', 'N', ..., 'N', 'N', ''], dtype=object)
- lon(time)float64...
- standard_name :
- longitude
- long_name :
- WGS84 datum/longitude
- units :
- degree_east
- axis :
- X
array([ nan, 15.50167 , 15.50167 , ..., 15.501665, 15.501665, nan])
- lon_dir(time)object...
array(['', 'E', 'E', ..., 'E', 'E', ''], dtype=object)
- vs(time)float64...
- standard_name :
- platform_vertical_speed
- long_name :
- vertical speed
- coordiantes :
- lon lat alt
- units :
- m/s
array([nan, 0., -0., ..., -0., 0., nan])
- gs(time)float64...
- standard_name :
- platform_speed_wrt_ground
- long_name :
- groundspeed of platform
- coordiantes :
- lon lat alt
- units :
- kts
array([0. , 0. , 0. , ..., 3.19, 3.2 , 3.19])
- pitch(time)float64...
- standard_name :
- platform_pitch_fore_up
- long_name :
- pitch angle of platform
- coordiantes :
- lon lat alt
- units :
- degrees
array([11.61, 11.61, 11.61, ..., 11.23, 11.23, 11.23])
- roll(time)float64...
- standard_name :
- platform_roll_starboard_down
- long_name :
- roll angle of platform
- coordiantes :
- lon lat alt
- units :
- degrees
array([1.21, 1.21, 1.22, ..., 1.33, 1.33, 1.33])
- heading(time)float64...
- standard_name :
- platform_yaw_fore_starboard
- long_name :
- true heading
- coordiantes :
- lon lat alt
- units :
- degrees
array([-76.76, -76.76, -76.76, ..., -71.94, -71.94, -71.95])
- description :
- 1Hz subset based on GPS1 and INS data processed by AWI engineers
- instruments :
- GPS1 and INS
- version :
- [0.1]
- contact :
- mario.mech@uni-koeln.de, martin.gehrmann@awi.de
- institution :
- ['Alfred-Wegener-Institut Helmholtz-Zentrum für Polar- und Meeresforschung']
- author :
- Dr. Mario Mech
- source :
- DSHIP excerpt
- Convention :
- CF-1.8
- featureType :
- trajectory
- mission :
- AFLUX
- platform :
- Polar5
- flight_id :
- RF10
- title :
- Polar5 position and attitude data
- history :
- acquired by Polar5 during AFLUX campaign, quality checked by AWI and uploaded to DSHIP database, extracted and reformated by Mario Mech
The dataset includes the aircraft’s position (lon, lat, alt), attitude (roll, pitch, heading), and the ground speed, vertical speed and true air speed (gs, vs, tas).
Load Polar 5 flight phase information¶
Polar 5 flights are divided into segments to easily access start and end times of flight patterns. For more information have a look at the respective github repository.
At first we want to load the flight segments of (AC)³airborne
meta = ac3airborne.get_flight_segments()
The following command lists all flight segments into the dictionary segments
segments = {s.get("segment_id"): {**s, "flight_id": flight["flight_id"]}
for platform in meta.values()
for flight in platform.values()
for s in flight["segments"]
}
In this example we want to look at a racetrack pattern during ACLOUD RF10
seg = segments["AFLUX_P5_RF10_rt01"]
Using the start and end times of the segment, we slice the data to this flight section.
ds_gps_ins_rt = ds_gps_ins.sel(time=slice(seg["start"], seg["end"]))
Plots¶
%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import matplotlib.colors as mcolors
import numpy as np
import ipyleaflet
from simplification.cutil import simplify_coords_idx
plt.style.use("../mplstyle/book")
Plot all flights¶
def simplify_dataset(ds, tolerance):
indices_to_take = simplify_coords_idx(np.stack([ds.lat.values, ds.lon.values], axis=1), tolerance)
return ds.isel(time=indices_to_take)
# define colors for the flight tracks
colors = [mcolors.to_hex(c)
for c in plt.cm.inferno(np.linspace(0, 1, len(cat['Polar5']['GPS_INS'])))]
m = ipyleaflet.Map(basemap=ipyleaflet.basemaps.Esri.NatGeoWorldMap,
center=(80., 6), zoom=3)
for flight_id, color in zip(cat['Polar5']['GPS_INS'], colors):
# read gps dataset of flight
ds = cat.Polar5.GPS_INS[flight_id].to_dask()
# slice to takeoff and landing times
ds = ds.sel(time=slice(meta['P5'][flight_id]['takeoff'], meta['P5'][flight_id]['landing']))
# reduce dataset for plotting
ds_reduced = simplify_dataset(ds, tolerance=1e-5)
track = ipyleaflet.Polyline(
locations=np.stack([ds_reduced.lat.values,
ds_reduced.lon.values], axis=1).tolist(),
color=color,
fill=False,
weight=2,
name=flight_id)
m.add_layer(track)
m.add_control(ipyleaflet.ScaleControl(position='bottomleft'))
m.add_control(ipyleaflet.LegendControl(dict(zip(cat['Polar5']['GPS_INS'], colors)),
name="Flights",
position="bottomright"))
m.add_control(ipyleaflet.LayersControl(position='topright'))
m.add_control(ipyleaflet.FullScreenControl())
display(m)
Plot time series of one flight¶
fig, ax = plt.subplots(9, 1, sharex=True)
kwargs = dict(s=1, linewidths=0, color='k')
ax[0].scatter(ds_gps_ins.time, ds_gps_ins['alt'], **kwargs)
ax[0].set_ylabel('alt [m]')
ax[1].scatter(ds_gps_ins.time, ds_gps_ins['lon'], **kwargs)
ax[1].set_ylabel('lon [°E]')
ax[2].scatter(ds_gps_ins.time, ds_gps_ins['lat'], **kwargs)
ax[2].set_ylabel('lat [°N]')
ax[3].scatter(ds_gps_ins.time, ds_gps_ins['roll'], **kwargs)
ax[3].set_ylabel('roll [°]')
ax[4].scatter(ds_gps_ins.time, ds_gps_ins['pitch'], **kwargs)
ax[4].set_ylabel('pitch [°]')
ax[5].scatter(ds_gps_ins.time, ds_gps_ins['heading'], **kwargs)
ax[5].set_ylim(-180, 180)
ax[5].set_ylabel('heading [°]')
ax[6].scatter(ds_gps_ins.time, ds_gps_ins['gs'], **kwargs)
ax[6].set_ylabel('gs [kts]')
ax[7].scatter(ds_gps_ins.time, ds_gps_ins['vs'], **kwargs)
ax[7].set_ylabel('vs [m/s]')
ax[8].scatter(ds_gps_ins.time, ds_gps_ins['tas'], **kwargs)
ax[8].set_ylabel('tas [m/s]')
ax[-1].xaxis.set_major_formatter(mdates.DateFormatter('%H:%M'))
plt.show()
Plot time series of racetrack pattern¶
fig, ax = plt.subplots(9, 1, sharex=True)
kwargs = dict(s=1, linewidths=0, color='k')
ax[0].scatter(ds_gps_ins_rt.time, ds_gps_ins_rt['alt'], **kwargs)
ax[0].set_ylabel('alt [m]')
ax[1].scatter(ds_gps_ins_rt.time, ds_gps_ins_rt['lon'], **kwargs)
ax[1].set_ylabel('lon [°E]')
ax[2].scatter(ds_gps_ins_rt.time, ds_gps_ins_rt['lat'], **kwargs)
ax[2].set_ylabel('lat [°N]')
ax[3].scatter(ds_gps_ins_rt.time, ds_gps_ins_rt['roll'], **kwargs)
ax[3].set_ylabel('roll [°]')
ax[4].scatter(ds_gps_ins_rt.time, ds_gps_ins_rt['pitch'], **kwargs)
ax[4].set_ylabel('pitch [°]')
ax[5].scatter(ds_gps_ins_rt.time, ds_gps_ins_rt['heading'], **kwargs)
ax[5].set_ylim(-180, 180)
ax[5].set_ylabel('heading [°]')
ax[6].scatter(ds_gps_ins_rt.time, ds_gps_ins_rt['gs'], **kwargs)
ax[6].set_ylabel('gs [kts]')
ax[7].scatter(ds_gps_ins_rt.time, ds_gps_ins_rt['vs'], **kwargs)
ax[7].set_ylabel('vs [m/s]')
ax[8].scatter(ds_gps_ins_rt.time, ds_gps_ins_rt['tas'], **kwargs)
ax[8].set_ylabel('tas [m/s]')
ax[-1].xaxis.set_major_formatter(mdates.DateFormatter('%H:%M'))
plt.show()